package group.rober.saber.kit;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

import groovy.lang.GroovyObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Transient;

import static org.apache.commons.beanutils.BeanUtilsBean.*;

/**
 * Created by tisir<yangsong158@qq.com> on 2017-05-07
 * avaBean操作工具
 */
public abstract class BeanKit extends BeanUtils{
    private static Logger logger = LoggerFactory.getLogger(BeanKit.class);


    public static boolean propertyExists(Object object,String propertyName){
        try{
            BeanUtils.getProperty(object, propertyName);
            return true;
        }catch(NoSuchMethodException e){
            return false;
        }catch(IllegalAccessException e){
            return false;
        }catch(InvocationTargetException e){
            return false;
        }catch(Exception e){
            return false;
        }
    }

    /**
     * 复制javaBean属性
     * @param source 数据源对象
     * @param target 复制对的目标对象
     */
    public static void copyProperties(Object source, Object target){
        try {
            org.apache.commons.beanutils.BeanUtils.copyProperties(target,source);
        } catch (IllegalAccessException e) {
            logger.warn("copyProperties error ", e);
        } catch (InvocationTargetException e) {
            logger.warn("copyProperties error ", e);
        }
    }

    @SuppressWarnings("unchecked")
	public static <T> T castTo(Object orig,Class<T> requiredType){
        if(orig==null)return null;
        try {
            Object object = requiredType.newInstance();
            copyProperties(orig,object);
            return (T)object;
        } catch (InstantiationException e) {
            logger.error("",e);
            throw new RuntimeException("", e);
        } catch (IllegalAccessException e) {
            logger.error("",e);
            throw new RuntimeException("", e);
        }
    }

    public static <T> List<T> castListTo(List<?> origList, Class<T> requiredType){
        if(origList==null)return null;
        List<T> objectList = new ArrayList<T>();
        for(Object object:origList){
            objectList.add(castTo(object,requiredType));
        }
        return objectList;
    }

    /**
     * JavaBean转为Map
     * @param bean
     * @return
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static final Map<String, Object> bean2Map(Object bean) {
        Map<String, Object> returnMap = new LinkedHashMap<String, Object>();
        BeanInfo beanInfo;
        try {
            beanInfo = Introspector.getBeanInfo(bean.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i< propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if("class".equals(propertyName)){
                    continue;
                }
                //Groovy要忽略getMetaClass
                if(bean instanceof GroovyObject &&"metaClass".equals(propertyName)){
                    continue;
                }


                Method readMethod = descriptor.getReadMethod();
                if(readMethod.isAnnotationPresent(Transient.class))continue;//忽略掉不需要持久化的
//                Transient transient_ = readMethod.getAnnotation(Transient.class);
//                if(transient_!=null)continue;
                Object result = readMethod.invoke(bean, new Object[0]);
                returnMap.put(propertyName, result);
//                if (result != null) {
//                    returnMap.put(propertyName, result);
//                } else {
//                    returnMap.put(propertyName, null);
//                }
            }
        } catch (IntrospectionException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return returnMap;
    }


    public static <T> T map2Bean(Map<String, Object> map, Class<T> clazz) {
        T bean = null;
        try {
            bean = clazz.newInstance();
            org.apache.commons.beanutils.BeanUtils.populate(bean, map);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return bean;
    }
    public static <T> List<T> map2BeanList(List<Map<String,Object>> mapList, Class<T> clazz) {
        List<T> beanList = new ArrayList<T>();

        for(int i=0;i<mapList.size();i++){
            Map<String,Object> jsonItem = (Map<String,Object>)mapList.get(i);
            T beanItem = map2Bean(jsonItem,clazz);
            beanList.add(beanItem);
        }

        return beanList;
    }

    public static void setPropertyValue(final Object object, final String name, final Object value){
        if(BeanKit.propertyExists(object,name)){
            try {
                BeanKit.setProperty(object,name,value);
            } catch (IllegalAccessException e) {
                logger.warn("",e);
            } catch (InvocationTargetException e) {
                logger.warn("",e);
            }
        }
    }

    public static Object getPropertyValue(final Object bean, final String name) {
        try {
            return BeanUtilsBean.getInstance().getPropertyUtils().getNestedProperty(bean,name);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }
}
